{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Lesson 4\n",
    "\n",
    "Python Basic, Lesson 4, v1.0.1, 2016.12 by David.Yi      \n",
    "Python Basic, Lesson 4, v1.0.2, 2017.03 modified by Yimeng.Zhang\n",
    "\n",
    "### 上次内容要点\n",
    "\n",
    "* 列表的切片用法\n",
    "* 函数用法\n",
    "    \n",
    "### 本次内容要点\n",
    "\n",
    "* 日期库 datetime 用法介绍，datetime、time 等库的介绍，获得日期，字符串和日期转换，日期格式介绍，日期加减计算\n",
    "* 函数不同参数形式介绍和举例 \n",
    "* 匿名函数 lambda\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I guess: 500\n",
      "Please tell me big or small:big\n",
      "I guess: 250\n",
      "Please tell me big or small:small\n",
      "I guess: 375\n",
      "Please tell me big or small:big\n",
      "I guess: 312\n",
      "Please tell me big or small:small\n",
      "I guess: 343\n",
      "Please tell me big or small:big\n",
      "I guess: 327\n",
      "Please tell me big or small:small\n",
      "I guess: 335\n",
      "Please tell me big or small:big\n",
      "I guess: 331\n",
      "Please tell me big or small:small\n",
      "I guess: 333\n",
      "Please tell me big or small:ok\n",
      "HAHAHA\n"
     ]
    }
   ],
   "source": [
    "# 举例\n",
    "# 猜数，机器猜\n",
    "\n",
    "min = 0\n",
    "max = 1000\n",
    "\n",
    "guess_ok_mark = False\n",
    "\n",
    "while not guess_ok_mark:\n",
    "\n",
    "    cur_guess = int((min + max) / 2)\n",
    "    print('I guess:', cur_guess)\n",
    "    human_answer = input('Please tell me big or small:')\n",
    "    if human_answer == 'big':\n",
    "        max = cur_guess\n",
    "    if human_answer == 'small':\n",
    "        min = cur_guess\n",
    "    if human_answer == 'ok':\n",
    "        print('HAHAHA')\n",
    "        guess_ok_mark = True"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 日期处理\n",
    "\n",
    "datetime 是Python处理日期和时间的标准库，用于获取日期和进行日期计算等。\n",
    "\n",
    "需要理解 timestamp，UTC标准时区，时差这些概念。\n",
    "\n",
    "Python 的日期相关的标准库比较多（略有杂乱），有 datetime, time, calendar。\n",
    "\n",
    "datetime 库包括 date 日期，time 时间， datetime 日期和时间，tzinfo 时区，timedelta 时间跨度计算 等主要对象。\n",
    "\n",
    "获取当前日期和时间：`now = datetime.now()`\n",
    "\n",
    "日期戳和日期的区别，日期戳更加精确，日期只是年月日\n",
    "根据需要使用，大多数情况下只需要日期即可\n",
    "\n",
    "Time 对于时间的处理更加精确，用时间戳的表达方式\n",
    "\n",
    "时间戳定义为格林威治时间1970年01月01日00时00分00秒起至现在的总秒数，时间戳是惟一的\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2017-07-07 12:38:54.969064\n",
      "2017-07-07\n",
      "1499402334.9690642\n"
     ]
    }
   ],
   "source": [
    "# 显示今天日期\n",
    "# 显示今天 datetime 和 time\n",
    "\n",
    "from datetime import datetime, date\n",
    "import time\n",
    "\n",
    "print(datetime.now())\n",
    "print(date.today())\n",
    "print(time.time())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'datetime.datetime'>\n",
      "<class 'datetime.date'>\n",
      "<class 'float'>\n"
     ]
    }
   ],
   "source": [
    "# 各种日期时间类型的数据类型\n",
    "\n",
    "print(type(datetime.now()))\n",
    "print(type(date.today()))\n",
    "print(type(time.time()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1499402337.276191\n",
      "1499402337.276191\n",
      "1499402337.276191\n",
      "1499402337.276191\n",
      "1499402337.276191\n",
      "1499402337.276191\n",
      "1499402337.276191\n",
      "1499402337.276191\n",
      "1499402337.276191\n",
      "1499402337.276191\n"
     ]
    }
   ],
   "source": [
    "# 连续运行显示时间戳，看看时间戳差了多少毫秒\n",
    "\n",
    "for i in range(10):\n",
    "    print(time.time())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "time: 0.014995813369750977\n"
     ]
    }
   ],
   "source": [
    "# 用 time() 来计时，算10万次平方，看看哪台电脑速度快\n",
    "import time\n",
    "a = time.time()\n",
    "for i in range(100000):\n",
    "    j = i * i \n",
    "\n",
    "b = time.time()\n",
    "    \n",
    "print('time:', b-a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "#### 日期库-字符串和日期的转换\n",
    "\n",
    "字符串转化为日期：datetime.strptime()\n",
    "\n",
    "日期转换为字符串：datetime.strftime()\n",
    "\n",
    "日期字符串格式，举例\n",
    "\n",
    "```python\n",
    "cday1 = datetime.now().strftime('%a, %b %d %H:%M')\n",
    "cday2 = datetime.now().strftime('%A, %b %d %H:%M, %j')\n",
    "cday3 = datetime.now().strftime('%Y-%m-%d %H:%M:%S')\n",
    "```\n",
    "\n",
    "#### 日期库 – 日期格式说明\n",
    "\n",
    "* %a 英文星期的简写 (shorthand of week in English)\n",
    "* %A 英文星期的完整拼写 (longhand of week in English)\n",
    "* %b 英文月份的简写 (shorthand of month in English)\n",
    "* %B 英文月份的完整拼写 (longhand of month in English)\n",
    "* %c 本地当前的日期与时间 (current local date and time)\n",
    "* %d 日期数, 1-31之间 (date, between 1-31))\n",
    "* %H 小时数, 00-23之间 (hour, between 00-23))\n",
    "* %I 小时数, 01-12之间 (hour, between 01-12)\n",
    "* %m 月份, 01-12之间 (month, between 01-12)\n",
    "* %M 分钟数, 01-59之间 (minute, 01-59)\n",
    "* %j 本年从第1天开始计数到当天的天数 (total days from 1st day of this year till now)\n",
    "* %w 星期数, 0-6之间(0是周日)  (day of the week, between 0-6, 0=Sunday)\n",
    "* %W 当天属于本年的第几周,周一作为一周的第一天进行计算 (week of the year, starting with Monday )\n",
    "* %x 本地的当天日期 (local date)\n",
    "* %X 本地的当前时间 (local time)\n",
    "* %y 年份,0-99之间 (year, between 0-99)\n",
    "* %Y 年份的完整拼写 (longhand of year)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2017-01-02 18:19:59\n",
      "<class 'datetime.datetime'>\n",
      "\n",
      "\n",
      "2017, 19, 05 11 12:46\n",
      "<class 'str'>\n"
     ]
    }
   ],
   "source": [
    "# 字符串转化为日期\n",
    "\n",
    "dday = datetime.strptime('2017-1-2 18:19:59', '%Y-%m-%d %H:%M:%S')\n",
    "print(dday)\n",
    "print(type(dday))\n",
    "print('\\n')\n",
    "\n",
    "# 日期转换为字符串\n",
    "\n",
    "day1 = datetime.now().strftime('%Y, %W, %m %d %H:%M')\n",
    "print(day1)\n",
    "print(type(day1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sun, Mar 19 11:28\n",
      "Sunday, Mar 19 11:28, 078\n",
      "2017-03-19 11:28:19\n"
     ]
    }
   ],
   "source": [
    "# 日期转换为字符串，各种格式\n",
    "\n",
    "cday1 = datetime.now().strftime('%a, %b %d %H:%M')\n",
    "cday2 = datetime.now().strftime('%A, %b %d %H:%M, %j')\n",
    "cday3 = datetime.now().strftime('%Y-%m-%d %H:%M:%S')\n",
    "print(cday1)\n",
    "print(cday2)\n",
    "print(cday3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "time.struct_time(tm_year=2017, tm_mon=5, tm_mday=11, tm_hour=12, tm_min=47, tm_sec=34, tm_wday=3, tm_yday=131, tm_isdst=0)\n",
      "time.struct_time(tm_year=2017, tm_mon=5, tm_mday=11, tm_hour=12, tm_min=47, tm_sec=34, tm_wday=3, tm_yday=131, tm_isdst=0)\n",
      "<class 'time.struct_time'>\n"
     ]
    }
   ],
   "source": [
    "# 格式化时间戳为本地的时间 converts number of seconds to local time\n",
    "\n",
    "print(time.localtime(time.time()))\n",
    "print(time.localtime())  # If secs is not provided or None, the current time as returned by time() is used\n",
    "\n",
    "print(type(time.localtime(time.time())))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2017-03-19 11:02:10\n",
      "<class 'str'>\n"
     ]
    }
   ],
   "source": [
    "# 本地时间转换为字符串\n",
    "\n",
    "t = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())\n",
    "print(t)\n",
    "print(type(t))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "#### 日期计算\n",
    "\n",
    "对日期和时间进行加减实际上就是把 datetime 往后或往前计算，得到新的 datetime，需要导入 datetime 的 timedelta 类。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2017-05-11 12:48:38.858528\n",
      "2017-05-11 02:48:38.858528\n"
     ]
    }
   ],
   "source": [
    "# 日期计算\n",
    "# timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)\n",
    "\n",
    "from datetime import timedelta\n",
    "\n",
    "now = datetime.now()\n",
    "now1 = now + timedelta(hours=-10)\n",
    "print(now)\n",
    "print(now1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2017-03-22 12:47:45.586054\n",
      "2017-03-22 23:07:35.586054\n"
     ]
    }
   ],
   "source": [
    "# 日期的各个变量的计算\n",
    "\n",
    "now = datetime.now()\n",
    "now1 = now + timedelta(hours=10, minutes=20, seconds=-10)\n",
    "print(now)\n",
    "print(now1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "### 函数不同参数形式\n",
    "\n",
    "#### 位置参数和默认参数\n",
    "\n",
    "位置参数：必须按照顺序准确传递，如果数量和顺序不对，就会可能造成程序错误；调用函数时候，如果写了参数名称，那么位置就不重要了。        \n",
    "默认参数：在参数申明的时候跟一个用于默认值的赋值语句，如果调用函数的时候没有给出值，那么这个赋值语句就执行。\n",
    "\n",
    "注意：所有必须的参数要在默认参数之前\n",
    "\n",
    "默认参数的好处：\n",
    "* 减少程序复杂度\n",
    "* 降低程序错误可能性\n",
    "* 更好的兼容性\n",
    "\n",
    "#### 可变长度的参数-元组和字典\n",
    "\n",
    "可变长度的参数，分为不提供关键字和提供关键字两种模式，分别为元组 tuple 和字典 dict。\n",
    "\n",
    "可变长度的参数，如果是提供关键字，就是字典 dict，需要提供 key – value。\n",
    "\n",
    "将字典作为参数传递的时候，可以直接传一个字典变量，也可以在参数列表中写明 key 和 value。\n",
    "\n",
    "\n",
    "函数参数小结\n",
    "\n",
    "* 位置参数\n",
    "* 默认参数\n",
    "* 元组参数，一个星号\n",
    "* 字典参数，两个星号，需要传递 key 和 value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "110.0\n",
      "120.0\n",
      "130.0\n"
     ]
    }
   ],
   "source": [
    "# 函数默认参数\n",
    "\n",
    "def cal_0(money, rate=0.1):\n",
    "    return money + money * rate \n",
    "\n",
    "print(cal_0(100))\n",
    "print(cal_0(100,0.2))\n",
    "print(cal_0(rate=0.3,money=100))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "61000\n",
      "62000\n",
      "52000\n"
     ]
    }
   ],
   "source": [
    "# 函数默认参数\n",
    "\n",
    "def cal_1(money, bonus=1000, month=12，a=1,b=2):\n",
    "    i = money * month + bonus \n",
    "    return i\n",
    "\n",
    "print(cal_1(5000))\n",
    "print(cal_1(5000, 2000))\n",
    "print(cal_1(5000, 2000, 10))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 画一个三角形 ，n=高度\n",
    "'''\n",
    "       *\n",
    "      ***\n",
    "     *****\n",
    "    *******\n",
    "   *********\n",
    "  ***********\n",
    " *************\n",
    "\n",
    "''' "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "    \n",
      "   *\n",
      "  ***\n",
      " *****\n"
     ]
    }
   ],
   "source": [
    "# 函数默认参数\n",
    "\n",
    "def draw_triangle(n=5):\n",
    "\n",
    "    for i in range(n+1):\n",
    "        print(' '*(n-i),'*'*(2*i-1))\n",
    "        \n",
    "draw_triangle(3)\n",
    "#draw_triangle()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.5\n"
     ]
    }
   ],
   "source": [
    "# 函数可变长度的参数 元组\n",
    "\n",
    "def cal_2(kind, *numbers):\n",
    "    if kind == 'avg':\n",
    "        n = 0\n",
    "        for i in numbers:\n",
    "            n = n + i\n",
    "        return n / len(numbers)\n",
    "\n",
    "print(cal_2('avg', 1,2,3,4))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.5\n",
      "10\n",
      "10\n"
     ]
    }
   ],
   "source": [
    "# 函数可变长度的参数 元组\n",
    "# 输入类别，输入要计算的数字\n",
    "\n",
    "def cal_3(kind, *numbers):\n",
    "    \n",
    "    if kind == 'avg':\n",
    "        n = 0\n",
    "        for i in numbers:\n",
    "            n = n + i\n",
    "        return n / len(numbers)\n",
    "    if kind == 'sum':\n",
    "        n = 0\n",
    "        for i in numbers:\n",
    "            n = n + i\n",
    "        return n\n",
    "    \n",
    "print(cal_3('avg', 1,2,3,4))\n",
    "print(cal_3('sum', 1,2,3,4))\n",
    "\n",
    "# 如果已经有一个list或者tuple，要调用一个可变参数怎么办?\n",
    "# 在list或tuple前面加一个*号，把list或tuple的元素变成可变参数传进去：\n",
    "print(cal_3('sum',*[1,2,3,4]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.5\n",
      "10\n"
     ]
    }
   ],
   "source": [
    "# 函数可变长度的参数 元组\n",
    "# 简化程序逻辑\n",
    "\n",
    "def cal_4(kind, *numbers):\n",
    "    \n",
    "    n = 0\n",
    "    for i in numbers:\n",
    "        n = n + i\n",
    "    \n",
    "    if kind == 'avg':\n",
    "        return n / len(numbers)\n",
    "    if kind == 'sum':\n",
    "        return n\n",
    "    \n",
    "print(cal_4(kind='avg', 1,2,3,4))\n",
    "print(cal_4('sum', 1,2,3,4))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10\n"
     ]
    }
   ],
   "source": [
    "# 传递元组和字典参数的最合适写法\n",
    "\n",
    "def cal_5(*numbers, **kw):\n",
    "    \n",
    "    # 判断是否有 kind 这个 key\n",
    "    if 'kind' in kw:\n",
    "        kind_value = kw.get('kind')\n",
    "    \n",
    "    n = 0\n",
    "    for i in numbers:\n",
    "        n = n + i\n",
    "        \n",
    "    if kind_value == 'avg':\n",
    "        return n / len(numbers)\n",
    "    if kind_value == 'sum':\n",
    "        return n\n",
    "    \n",
    "print(cal_5(1,2,3,4,kind='avg',max='ignore'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "### 匿名函数\n",
    "\n",
    "Python 允许用 lambda 关键字创造匿名函数。\n",
    "lambda 匿名函数不需要常规函数的 def 和 return 关键字，因为匿名函数代码较短，因此适用于一些简单处理运算的场景。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 等价的函数一般写法和匿名函数写法\n",
    "\n",
    "def add(x, y):\n",
    "    return x + y\n",
    "\n",
    "lambda x, y: x + y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a =  lambda x, y=2 : x + y \n",
    "a(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "8"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a(3, 5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "44\n"
     ]
    }
   ],
   "source": [
    "a = lambda x : x * x +40\n",
    "\n",
    "print(a(2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "思考一下\n",
    "\n",
    "* 计算一个正整数的因数\n",
    "* 写一个寻找列表中最大数的函数（不用列表排序方法）"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
